package net.redxyz.repost.resource;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;

import org.zhiqim.httpd.HttpRequest;
import org.zhiqim.httpd.HttpSession;
import org.zhiqim.kernel.annotation.AnAlias;
import org.zhiqim.kernel.logging.Log;
import org.zhiqim.kernel.logging.LogFactory;
import org.zhiqim.kernel.util.Validates;

import com.xiyuan.util.json.JsonConfig;
import com.xiyuan.util.json.Jsons;

import net.redxyz.top.TaobaoInvokeFailureException;
import net.redxyz.top.message.TaobaoResponse;

/***
 * APP 数据交互响应工具类类
 * 
 * @author Administrator
 * 
 */
public class AppResp
{
    private static Log log = LogFactory.getLog(AppResp.class);
    /********************************************************************/
    // 以下是错误码定义
    /********************************************************************/
    
    public static final int login = -100;// 用户需要登录
    public static final int login_w2 = -99;// 需要二次授权
    public static final int success_tips = 1;// 用户需要登录
    /** 响应码 成功 */
    public static final int success = 0;// 用户需要登录
    /** 响应码 用户订购版本过低 */
    public static final int code_app_permission_not_open = 109;// app 为开放
    /** 响应码 用户订购版本过低 */
    public static final int code_app_permission_lower = 201;// 用户订购版本过低
    /** 服务端重定向 */
    public static final int code_app_redirect = 301;// 服务端重定向 从301 开始 后续皆为 http相应码
    /** 位置的转发地址 */
    public static final int code_app_forward_unkown_url = 400;// 转发错误地址
    /** 服务禁止访问 */
    public static final int code_app_forward_403 = 403;// 服务禁止访问
    // 错误码
    public static final int comm_error = 699;// 通用错误
    public static final int comm_alert_msg = 700;// 弹出错误信息
    public static final int comm_tips_msg = 701;// tips 提示
    
    // 扩展二级错误码
    public static final int not_exists = 1000;// 不存在
    public static final int part_success = 1100;// 部分成功
    
    static
    {
        try
        {
            JsonConfig.getDefault().registerAlias(AnAlias.class);// 注册字段JSON 别名
        }
        catch (Throwable e)
        {
            e.printStackTrace();
        }
    }
    
    /***
     * 响应客户端
     * 
     * @param request
     * @param code 页面错误吗
     * @param message 错误吗提示内容
     * @param data 业务数据
     * @throws Exception
     */
    protected static void doResponse(HttpRequest request, int code, String message, Object data) throws Exception
    {
        if (request.getResponse().isCommitted())
            return;
        
        int glmt = request.getContext().getAttributeInt("_lc_");// 单位时间分钟
        long lct = request.getContext().getAttributeLong("_lct_");
        
        int req_glmt = request.getParameterInt("_srv_glmt_");
        long ct = System.currentTimeMillis() / 1000;// 当前时间秒钟
        if (req_glmt > 0)
        {
            lct = ct + req_glmt * 60;
            request.getContext().setAttribute("_lct_", lct);// 参数过期时间
        }
        
        if (lct < ct || req_glmt <= 0)
            glmt = 0;// 参数 过期了重置
            
        HttpSession session = request.getSession();
        Map<String, Object> dataMap = new HashMap<String, Object>();
        boolean isSuccess = code == success || code == success_tips;
        dataMap.put("success", isSuccess);// 业务上的成功与失败
        dataMap.put("code", code);// 业务上的错误吗
        dataMap.put("msg", message);// 业务成功或者响应 描述，错误吗将在这里提示
        dataMap.put("data", data);// 业务成功或者响应 描述，错误吗将在这里提示
        dataMap.put("isRefreshSessionUser", session.getAttributeBoolean(SessionUser.modify_key, false));// 是否需要客户端刷新
                                                                                                        // sessionUser
        dataMap.put("sessionId", request.getSessionId());// 服务端的session对象
        dataMap.put("sessionKey", request.getContext().getSessionManager().getSessionIdName());
        
        // 端解密字段
        dataMap.put("_srv_glmt_", glmt > 0 ? glmt : 0);
        
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("success", true);// 对于小程序来说全部都成功
        map.put("data", dataMap);
        
        /******** 这个部分是兼容老版本手机端小程序 ********************/
        int is_app_parser_appoint = request.getAttributeInt("is_app_parser_appoint");
        if (is_app_parser_appoint != 1 // 不是指定解析器的情况下
                && request.getAttributeInt("is_app_old_request") == 1)
        {
            String dataKey = request.getHeader("X-APP-Error-Data-Key");// 是否将成功穿为失败
            if (Validates.isEmptyBlank(dataKey))
            {// 这里老版本
                if (!isSuccess)
                {
                    map.put("success", false);
                    map.put("errorCode", code);
                    map.put("errorMessage", message);
                }
                else
                    map.put("data", data);
            }
        }
        /**************************************************/
        
        String resp_content = Jsons.toString(map);
        request.getResponse().setContentType("application/json");
        request.getResponse().print(resp_content);
        request.getResponse().commit();
        
        SessionUser user = request.getSessionUser(SessionUser.class);
        if (!isSuccess)
            log.error( (user == null ? "guest" : user.getNickLogined()) + " error:" + Jsons.toString(dataMap) + "\r\n");
        
    }
    
    /***
     * 响应成功 并且附加提示信息<br>
     * tips提示信息(tip操作需要前端实现) 这里只是告知该操作是成功的操作
     * 
     * @param request
     * @param tips 提示信息
     * @param data
     * @throws Exception
     */
    public static void doResponseResult(HttpRequest request, String tips, Object data) throws Exception
    {
        doResponse(request, Validates.isNotEmptyBlank(tips) ? success_tips : success, tips, data);
    }
    
    /***
     * 响应成功
     * 
     * @param request
     * @param null,
     * @throws Exception
     */
    public static void doResponseResult(HttpRequest request) throws Exception
    {
        doResponse(request, success, null, null);
    }
    
    /***
     * 响应成功
     * 
     * @param request
     * @param data 相应内容
     * @param data
     * @throws Exception
     */
    public static void doResponseResult(HttpRequest request, Object data) throws Exception
    {
        doResponse(request, success, null, data);
    }
    
    /***
     * 响应成功 部分成功 code=0
     * 
     * @param request
     * @param data
     * @throws Exception
     */
    public static void doResponsePartSuccess(HttpRequest request, Object data) throws Exception
    {
        Map<String, Object> respMap = new HashMap<String, Object>();
        respMap.put("sub_code", part_success);
        respMap.put("ext_data", data);
        respMap.put("msg", null);
        doResponse(request, success, null, respMap);
    }
    
    /***
     * 响应成功 部分成功 code=0
     * 
     * @param request
     * @param data
     * @param message 部分成功的描述信息
     * @throws Exception
     */
    public static void doResponsePartSuccess(HttpRequest request, Object data, String message) throws Exception
    {
        Map<String, Object> respMap = new HashMap<String, Object>();
        respMap.put("sub_code", part_success);
        respMap.put("ext_data", data);
        doResponse(request, success, message, respMap);
    }
    
    public static void doResponseLogin(HttpRequest request, String message, Object data) throws Exception
    {
        doResponse(request, login, message, data);
    }
    
    public static void doResponseLoginW2(HttpRequest request, String message, Object data) throws Exception
    {
        doResponse(request, login_w2, message, data);
    }
    
    /**
     * 响应客户端需要登录
     * 
     * @param request
     * @throws Exception
     */
    public static void doResponseLogin(HttpRequest request) throws Exception
    {
        doResponse(request, login, "用户会话超时，请重新登录", null);
    }
    
    /**
     * 响应客户端 必须重新登录才可以调用
     * 
     * @param request
     * @throws Exception
     */
    public static void doResponseLoginW2(HttpRequest request) throws Exception
    {
        doResponse(request, login_w2, "用户会话超时，请重新登录", null);
    }
    
    /** 功能未开放 */
    public static void doResponseAppPermissionNotOpen(HttpRequest request, String msg, Object data) throws Exception
    {
        doResponse(request, code_app_permission_not_open, msg, data);
    }
    
    /***
     * 相应客户端 订购App 版本过低，需要弹处订购嘻嘻 才能操作
     * 
     * @param request
     * @param msg 错误描述
     * @param limit_app_verion 要求最低版本
     * @param limit_app_ver_name 要求最低版本名称
     * @throws Exception
     */
    public static void doResponseAppPermissionLower(HttpRequest request, String msg, int limit_app_verion, String limit_app_ver_name, Object extData) throws Exception
    {
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("limitAppVersion", limit_app_verion);
        dataMap.put("limitAppVersionName", limit_app_ver_name);
        dataMap.put("extData", extData);
        dataMap.put("msg", msg);
        
        doResponse(request, code_app_permission_lower, msg, dataMap);
    }
    
    /**
     * 响应一个异常错误信息
     * 
     * @param request
     * @param e
     * @throws Exception
     */
    public static void doResponseException(HttpRequest request, Throwable e) throws Exception
    {
        if (e instanceof TaobaoInvokeFailureException)
        {
            doResponseInvokeFailure(request, (TaobaoInvokeFailureException) e);
            return;
        }
        
        String msg = e.getMessage();
        if (msg == null || "null".equals(msg))
        {// 如果没有错误消息就输入异常栈信息
            StringWriter sw = new StringWriter();
            e.printStackTrace(new PrintWriter(sw));
            msg = sw.toString();
        }
        
        doResponseErrorAlert(request, msg);
        log.error(e);
    }
    
    /**
     * 响应 调用淘宝失败的错误信息到客户端，这里会自动响应 短授权
     * 
     * @param request
     * @param alert_msg 非短授权的错误提示信息，= null 是则使用 resp.getResponseText() 做提示内容
     * @param exception
     * @throws Exception
     */
    public static void doResponseInvokeFailure(HttpRequest request, TaobaoInvokeFailureException exception, String alert_msg) throws Exception
    {
        
        TaobaoResponse resp = ((TaobaoInvokeFailureException) exception).getResponse();
        if (resp.isInvalidSession() || resp.isW2())
        {
            AppResp.doResponseLoginW2(request, "用户session过期", resp.getResponseText());
            return;
        }
        
        AppResp.doResponseErrorAlert(request, alert_msg == null ? resp.getResponseText() : alert_msg);
    }
    
    /**
     * 响应 调用淘宝失败的错误信息到客户端，这里会自动响应 短授权
     * 
     * @param request
     * @param exception
     * @throws Exception
     */
    public static void doResponseInvokeFailure(HttpRequest request, TaobaoInvokeFailureException exception) throws Exception
    {
        String message = exception.getMessage();
        if (Validates.isEmptyBlank(message))
        {
            TaobaoResponse resp = exception.getResponse();
            message = resp != null ? resp.getErrorMsg() : null;
        }
        
        doResponseInvokeFailure(request, exception, Validates.isEmptyBlank(message) ? null : message);
    }
    
    /****
     * 设置响应通用信息，699，错误码
     * 
     * @param request
     * @throws Exception
     */
    public static void doResponseError(HttpRequest request, String message, Object data) throws Exception
    {
        doResponse(request, comm_error, message, data);
    }
    
    /****
     * 设置响应通用信息，700，错误码
     * 
     * @param request
     * @throws Exception
     */
    public static void doResponseErrorAlert(HttpRequest request, String message) throws Exception
    {
        doResponse(request, comm_alert_msg, message, null);
    }
    
    /****
     * 设置响应通用信息，700，错误码
     * 
     * @param request
     * @throws Exception
     */
    public static void doResponseErrorAlert(HttpRequest request, String message, Object data) throws Exception
    {
        doResponse(request, comm_alert_msg, message, data);
    }
    
    /****
     * 设置响应通用信息，700，错误码, 子错误码 1000
     * 
     * @param request
     * @throws Exception
     */
    public static void doResponseErrorAlertNotExists(HttpRequest request, String message) throws Exception
    {
        Map<String, Object> respMap = new HashMap<>();
        respMap.put("sub_code", not_exists);
        respMap.put("ext_data", null);
        doResponse(request, comm_alert_msg, message, respMap);
    }
    
    /****
     * 设置响应通用信息，700，错误码, 子错误码 1000
     * 
     * @param request
     * @throws Exception
     */
    public static void doResponseErrorAlertNotExists(HttpRequest request, String message, Object data) throws Exception
    {
        Map<String, Object> respMap = new HashMap<>();
        respMap.put("sub_code", not_exists);
        respMap.put("ext_data", data);
        doResponse(request, comm_alert_msg, message, respMap);
    }
    
    /****
     * 设置响应通用信息，701，错误码
     * 
     * @param request
     * @throws Exception
     */
    public static void doResponseErrorTips(HttpRequest request, String message, Object data) throws Exception
    {
        doResponse(request, comm_tips_msg, message, data);
    }
    
    /****
     * 设置响应通用信息，701，错误码
     * 
     * @param request
     * @throws Exception
     */
    public static void doResponseErrorTipsNotExists(HttpRequest request, String message, Object data) throws Exception
    {
        Map<String, Object> respMap = new HashMap<>();
        respMap.put("sub_code", not_exists);
        respMap.put("ext_data", data);
        doResponse(request, comm_tips_msg, message, respMap);
    }
    
    /** 相应重定向 */
    public static void doResponseRedirect(HttpRequest request, String url, String msg) throws Exception
    {
        doResponse(request, code_app_redirect, msg, url);
    }
    
    /** 相应重定向 */
    public static void doResponseForbidden(HttpRequest request, String msg) throws Exception
    {
        doResponse(request, code_app_forward_403, msg, null);
    }
    
    /**
     * 判断是否需要响应小程序格式数据
     * 
     * <br>
     * 这里只判断 请求头 X-RETURN-APP-DATA 是否为true;
     * 
     * @return
     */
    public static boolean isReturnAppData(HttpRequest request)
    {
        return "true".equalsIgnoreCase(request.getHeader("X-RETURN-APP-DATA"));
    }
    
    /**
     * 标记已经刷新用户
     * 
     * @param request
     */
    public static void doSessionUserRefreshed(HttpRequest request)
    {
        request.getSession().setAttribute(SessionUser.modify_key, false);
    }
    
}
